package com.ebeitech.auction.http;

import android.content.Context;
import android.view.View;

import com.ebeitech.auction.BuildConfig;
import com.ebeitech.auction.R;
import com.ebeitech.auction.application.EbeiApplication;
import com.ebeitech.auction.http.service.BaseSubscriber;
import com.ebeitech.auction.http.service.HttpAuctionServiceRx;
import com.ebeitech.auction.view.PublicUtil;
import com.ebeitech.library.constant.SPConstants;
import com.ebeitech.library.ui.dialog.CommonAlertDialogFragment;
import com.ebeitech.library.util.CommonUtil;
import com.ebeitech.library.util.Log;
import com.ebeitech.library.util.SPManager;
import com.ebeitech.library.util.StringUtil;
import com.ebeitech.library.util.ViewUtil;
import com.google.gson.Gson;

import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeUnit;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by alice on 2017/11/1.
 */
public class HttpService {

	// 一碑测试
//	public static final String SERVER_ADDRESS = "http://114.215.254.222:6902/la/";
	// 碧桂园测试
	public static final String SERVER_ADDRESS_BETA = "http://java-test.countrygarden.com.cn:8888/la/";
//	public static final String SERVER_ADDRESS = "http://10.10.169.53:8888/la/";

	// 碧桂园正式
	public static final String SERVER_ADDRESS_BUILD = "https://gis-tupai.countrygarden.com.cn/la/";

	public static String SERVER_ADDRESS = SERVER_ADDRESS_BETA;

	public static final String RESULT_CODE_SUCCESS = "1";

	private static HttpService mHttpService;

	private OkHttpClient client;
	private Retrofit rxRetrofit;
	private Retrofit rxGsonRetrofit;

	public static HttpService getInstance() {
		if (mHttpService == null) {
			mHttpService = new HttpService();
		}
		return mHttpService;
	}

	//返回正常实例
	public Retrofit getRxRetrofit() {
		if (rxRetrofit == null) {
			getServerAddress();
			rxRetrofit = new Retrofit.Builder()
					.baseUrl(SERVER_ADDRESS)
					.client(getHttpClient())
					.build();
		}
		return rxRetrofit;
	}

	public Retrofit getRxGsonRetrofit() {
		if (rxGsonRetrofit == null) {
			getServerAddress();
			rxGsonRetrofit = new Retrofit.Builder()
					.baseUrl(SERVER_ADDRESS)
					.client(getHttpClient())
					.addConverterFactory(GsonConverterFactory.create())
					.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
					.build();
		}
		return rxGsonRetrofit;
	}

	public String getServerAddress() {
		if (BuildConfig.FLAVOR.equals("build")) {
			SERVER_ADDRESS = SERVER_ADDRESS_BUILD;
		} else {
			SERVER_ADDRESS = SERVER_ADDRESS_BETA;
		}
		return SERVER_ADDRESS;
	}

	private OkHttpClient getHttpClient() {
		if (client == null) {
			client = new OkHttpClient.Builder().
					connectTimeout(60, TimeUnit.SECONDS).
					readTimeout(60, TimeUnit.SECONDS).
					writeTimeout(60, TimeUnit.SECONDS).
					addInterceptor(new Interceptor() {

						@Override
						public Response intercept(Chain chain) throws IOException {
							String client_token = SPManager.getInstance().get(SPConstants.CLIENT_TOKEN, "");
							Request original = chain.request();

							Request request = original.newBuilder()
									.addHeader("client_token", client_token)
									.build();

							return chain.proceed(request);
						}
					}).build();
		}
		return client;
	}

	public void resetHttp() {
		client = null;
	}

	public <T> void executeHttp(Context context, final Call<ResponseBody> call, final HttpListener<T> l, Class<T> classT) {
		executeHttp(context, call, l, classT, true);
	}

	public <T> void executeHttp(Context context, final Call<ResponseBody> call, final HttpListener<T> l, final Class<T> classT, boolean isProgressDialogVisible) {
		final BaseSubscriber<T> mBase = new BaseSubscriber<T>(context) {

			@Override
			public void onCompleted() {
				super.onCompleted();
			}

			@Override
			public void onError(EbeiErrorCode errorCode) {
				super.onError(errorCode);
				if (l != null) {
					l.onError(errorCode);
				}
			}

			@Override
			public void onNext(T t) {
				super.onNext(t);
			}

			@Override
			public void onStart() {
				super.onStart();
				if (l != null) {
					l.onStart();
				}
			}

			@Override
			public void onLoadData(T t) {
				super.onLoadData(t);
				if (l != null) {
					l.onSuccess(t);
				}
			}
		};
		mBase.setIsProgressDialogVisible(isProgressDialogVisible);

		Observable.create(new Observable.OnSubscribe<T>() {

			@Override
			public void call(Subscriber<? super T> subscriber) {
				retrofit2.Response<ResponseBody> response = null;
				try {
					response = call.execute();
					Log.d("json url = " + call.request().url());
					boolean isTokenValid = checkTokenIsValid(response);
					if (isTokenValid && response.isSuccessful()){
						String result = "";
						if (response.body() != null) {
							result = response.body().string();
						}
						Log.d("json result = " + result);
						if (String.class.getName().equals(classT.getName())) {
							subscriber.onNext((T) result);
						} else {
							T data = new Gson().fromJson(result, classT);
							subscriber.onNext(data);
						}
						subscriber.onCompleted();
					} else {
						String result = "";
						if (response.errorBody() != null) {
							result = response.errorBody().string();
						}
						if (!StringUtil.isEmpty(result) || !isTokenValid) {
							try {
								JSONObject jsonObject = new JSONObject();
								if (!isTokenValid) {
									jsonObject.put("ErrorCode", String.valueOf(EbeiErrorCode.ERROR_CODE_TOKEN_INVALID));
								} else {
									jsonObject.put("ErrorCode", response.code());
									jsonObject.put("ErrorMsg", response.message());
								}
								result = jsonObject.toString();
							} catch (Exception e) {}
						}
						Log.d("json result = " + result);
						subscriber.onError(new RuntimeException(result));
					}
				} catch (Exception e) {
					e.printStackTrace();
					subscriber.onError(e);
					return;
				}
			}
		}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(mBase);
	}

	public boolean checkTokenIsValid(retrofit2.Response response)  {
		if (response == null) {
			return false;
		}

		Headers headers = response.headers();
		if (headers.get("token_code") != null) {
			// 说明Token失效
			boolean isDialogShowing = SPManager.getInstance().get("isDialogShowing", false);
			if (isDialogShowing) {
				return false;
			}
			SPManager.getInstance().put("isDialogShowing", true);
			final Context context = EbeiApplication.getContext();// 防止context不正确,DialogFragment报错
			CommonAlertDialogFragment dialog = ViewUtil.getAlertDialog(context, "", context.getString(R.string.login_token_invalid_remind), new CommonAlertDialogFragment.OnBtnClickListener() {
				@Override
				public void onClick(View v, CommonAlertDialogFragment dialog) {
					ViewUtil.dismissDialog(dialog);
					PublicUtil.doLogout(context);
				}
			}, new CommonAlertDialogFragment.OnBtnClickListener() {

				@Override
				public void onClick(View v, CommonAlertDialogFragment dialog) {
					ViewUtil.dismissDialog(dialog);
					SPManager.getInstance().put("isDialogShowing", false);
				}
			}, "", "");
			dialog.setCancelButtonVisible(false);
			if (EbeiApplication.isAppAlive()) {
				ViewUtil.showDialog(context, dialog);
			}

			return false;
		}

		return true;
	}

	public void downloadFile(final Context context, final HttpListener<EbeiErrorCode> l, final HttpLoadListener loadListener, final String url) {
		final BaseSubscriber<EbeiErrorCode> mBase = new BaseSubscriber<EbeiErrorCode>(context) {

			@Override
			public void onCompleted() {
				super.onCompleted();
			}

			@Override
			public void onError(EbeiErrorCode errorCode) {
				super.onError(errorCode);
				if (l != null) {
					l.onError(errorCode);
				}
			}

			@Override
			public void onNext(EbeiErrorCode t) {
				super.onNext(t);
			}

			@Override
			public void onStart() {
				super.onStart();
				if (l != null) {
					l.onStart();
				}
			}

			@Override
			public void onLoadData(EbeiErrorCode t) {
				super.onLoadData(t);
				if (l != null) {
					l.onSuccess(t);
				}
			}
		};
		mBase.setIsProgressDialogVisible(false);

		final Call<ResponseBody> call = getRxRetrofit().create(HttpAuctionServiceRx.class).downloadFile(url);
		Observable.create(new Observable.OnSubscribe<EbeiErrorCode>() {

			@Override
			public void call(Subscriber<? super EbeiErrorCode> subscriber) {
				retrofit2.Response<ResponseBody> response = null;
				try {
					response = call.execute();

					if (checkTokenIsValid(response) && response.isSuccessful()){
						boolean writtenToDisk = false;
						if (response.body() != null) {
							String fileName = url;
							if (fileName.contains("/")) {
								String fileNameT = fileName.substring(fileName.lastIndexOf("/"));
								if (fileNameT.length() > 0) {
									fileName = fileNameT.substring(1);
								}
							}
							String filePath = CommonUtil.getCacheFile(context, "files") + File.separator + fileName;
							writtenToDisk = writeResponseBodyToDisk(context, response.body(), filePath, loadListener);
						}
						if (writtenToDisk) {
							subscriber.onNext(null);
						} else {
							subscriber.onNext(new EbeiErrorCode(-1));
						}
						subscriber.onCompleted();
					} else {
						String result = "";
						if (response.errorBody() != null) {
							result = response.errorBody().string();
						}
						if (StringUtil.isEmpty(result)) {
							try {
								if (!StringUtil.isEmpty(result)) {
									JSONObject jsonObject = new JSONObject(result);
									jsonObject.put("ErrorCode", response.code());
									jsonObject.put("ErrorMsg", response.message());
									result = jsonObject.toString();
								}
							} catch (Exception e) {}
						}
						Log.d("json result = " + result);
						subscriber.onError(new RuntimeException(result));
					}
				} catch (Exception e) {
					e.printStackTrace();
					subscriber.onError(e);
					return;
				}
			}
		}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(mBase);
	}

	private boolean writeResponseBodyToDisk(Context context, ResponseBody body, String fileName, final HttpLoadListener loadListener) {
		try {
			// todo change the file location/name according to your needs
			File futureStudioIconFile = new File(fileName);

			InputStream inputStream = null;
			OutputStream outputStream = null;

			try {
				if (futureStudioIconFile.exists()) {
					futureStudioIconFile.delete();
					futureStudioIconFile = new File(fileName);
				}
				byte[] fileReader = new byte[4096];

				long fileSize = body.contentLength();
				long fileSizeDownloaded = 0;

				inputStream = body.byteStream();
				outputStream = new FileOutputStream(futureStudioIconFile);

				while (true) {
					int read = inputStream.read(fileReader);

					if (read == -1) {
						break;
					}

					outputStream.write(fileReader, 0, read);

					fileSizeDownloaded += read;

					if (loadListener != null) {
						loadListener.onLoad(((int)(fileSizeDownloaded * 10000 / fileSize)) / (float)100);
					}

					Log.d("file download: " + fileSizeDownloaded + " of " + fileSize);
				}

				outputStream.flush();

				return true;
			} catch (IOException e) {
				return false;
			} finally {
				if (inputStream != null) {
					inputStream.close();
				}

				if (outputStream != null) {
					outputStream.close();
				}
			}
		} catch (IOException e) {
			return false;
		}
	}

	public interface HttpListener<T> {
		void onStart();
		void onError(EbeiErrorCode errorCode);
		void onSuccess(T result);
	}

	public interface HttpLoadListener {
		void onLoad(float progress);
	}

}
